import React, {
  useRef,
  useState,
  useEffect,
} from 'react'
import { withNativeProps } from '../../utils/native-props'
import { useIsomorphicUpdateLayoutEffect } from '../../hooks/use-isomorphic-update-layout-effect'
import { ImageIcon } from './imageIcon'
import { BrokenImageIcon } from './brokenImageIcon'
import type { ImageProps } from './type'
import { LazyDetector } from './lazyDetector'

function toCSSLength(val: string | number) {
  return typeof val === 'number' ? `${val}px` : val
}

const classPrefix = 'rt-image'

export const Image: React.FC<ImageProps> = (props) => {
  const {
    alt,
    crossOrigin,
    fit = 'fill',
    fallback = (
      <div className={`${classPrefix}-tip`}>
        <BrokenImageIcon />
      </div>
    ),
    height,
    lazy = false,
    src,
    onClick,
    onContainerClick,
    onError,
    onLoad,
    placeholder = (
      <div className={`${classPrefix}-tip`}>
        <ImageIcon />
      </div>
    ),
    width,
  } = props

  const [loaded, setLoaded] = useState(false)
  const [failed, setFailed] = useState(false)

  const imgRef = useRef<HTMLImageElement>(null)

  let actSrc: string | undefined = src
  const [initialized, setInitialized] = useState(!lazy)
  actSrc = initialized ? src : undefined

  useIsomorphicUpdateLayoutEffect(() => {
    setLoaded(false)
    setFailed(false)
  }, [actSrc])

  useEffect(() => {
    // for nextjs ssr
    if (imgRef.current?.complete) {
      setLoaded(true)
    }
  }, [])

  const renderInner = () => {
    if (failed) {
      return <>{fallback}</>
    }

    const img = (
      <img
        alt={alt}
        crossOrigin={crossOrigin}
        className={`${classPrefix}-img`}
        onClick={onClick}
        onLoad={(e) => {
          setLoaded(true)
          onLoad?.(e)
        }}
        onError={(e) => {
          setFailed(true)
          onError?.(e)
        }}
        // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
        role="button"
        ref={imgRef}
        src={actSrc}
        style={{
          objectFit: fit,
          display: loaded ? 'block' : 'none',
        }}
        tabIndex={0}
      />
    )

    return (
      <>
        {!loaded && placeholder}
        {img}
      </>
    )
  }

  const style: ImageProps['style'] = {}
  if (width) {
    style['--width'] = toCSSLength(width)
    style.width = toCSSLength(width)
  }
  if (height) {
    style['--height'] = toCSSLength(height)
    style.height = toCSSLength(height)
  }

  return withNativeProps(
    props,
    <div
      className={classPrefix}
      style={style}
      onClick={onContainerClick}
    >
      {lazy && !initialized && (
        <LazyDetector
          height={style.height as string}
          width={style.width as string}
          onActive={() => {
            setInitialized(true)
          }}
        />
      )}
      {renderInner()}
    </div>,
  )
}
